package cn.jbolt.ec.wx;


import cn.hutool.core.io.FileUtil;
import cn.jbolt.common.model.BecApp;
import com.github.binarywang.utils.qrcode.BufferedImageLuminanceSource;
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;

/**
 * 二维码生成和读的工具类
 *
 */
public class QrCodeCreateUtil {

    /**
     * 生成包含字符串信息的二维码图片
     * @param outputStream 文件输出流路径
     * @param content 二维码携带信息
     * @param qrCodeSize 二维码图片大小
     * @param imageFormat 二维码的格式
     * @throws WriterException
     * @throws IOException
     */
    public static boolean createQrCode(OutputStream outputStream,
                                       String content, int qrCodeSize,
                                       String imageFormat) throws WriterException, IOException{
        //设置二维码纠错级别ＭＡＰ
        Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<EncodeHintType, ErrorCorrectionLevel>();
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);  // 矫错级别
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        //创建比特矩阵(位矩阵)的QR码编码的字符串
        BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hintMap);
        // 使BufferedImage勾画QRCode  (matrixWidth 是行二维码像素点)
        int matrixWidth = byteMatrix.getWidth();
        BufferedImage image = new BufferedImage(matrixWidth-200, matrixWidth-200, BufferedImage.TYPE_INT_RGB);
        image.createGraphics();
        Graphics2D graphics = (Graphics2D) image.getGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, matrixWidth, matrixWidth);
        // 使用比特矩阵画并保存图像
        graphics.setColor(Color.BLACK);
        for (int i = 0; i < matrixWidth; i++){
            for (int j = 0; j < matrixWidth; j++){
                if (byteMatrix.get(i, j)){
                    graphics.fillRect(i-100, j-100, 1, 1);
                }
            }
        }
        return ImageIO.write(image, imageFormat, outputStream);
    }

    /**
     * 读二维码并输出携带的信息
     */
    public static void readQrCode(InputStream inputStream) throws IOException{
        //从输入流中获取字符串信息
        BufferedImage image = ImageIO.read(inputStream);
        //将图像转换为二进制位图源
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        Result result = null ;
        try {
            result = reader.decode(bitmap);
        } catch (ReaderException e) {
            e.printStackTrace();
        }
    }

    /**
     *生成带头像的二维码

     * @param codeSavePath
     * @param pictureSavePath
     * @throws IOException
     */
    public static void gen_logo_qrcode(String codeSavePath,String pictureSavePath)  {
        try{
            BufferedImage image= ImageIO.read(new File(pictureSavePath));
            BufferedImage bg= ImageIO.read(new File(codeSavePath));
            bg= new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(bg, null);  //这句一定不能丢，否则生成的logo二维码logo是灰色的
            Graphics g=bg.createGraphics();
            int width=image.getWidth(null) > bg.getWidth() * 2/10? (bg.getWidth() * 2/10) : image.getWidth(null);
            int height=image.getHeight(null) > bg.getHeight() * 2/10? (bg.getHeight() * 2/10) : image.getWidth(null);
            g.drawImage(image,(bg.getWidth()- width)/2,(bg.getHeight()-height)/2,width,height,null);
            g.dispose();

            bg.flush();
            image.flush();

            FileUtil.del(codeSavePath);     //删除该目录下的单纯二维码文件
            FileUtil.del(pictureSavePath);     //删除该目录下的单纯微信头像文件

            ImageIO.write(bg,"png", new File(codeSavePath));

        }catch (IOException e){

        }
    }

    /**
     * 根据网络图片地址下载图片
     * @param fileUrl
     */
    public static String download_picture(String fileUrl,String head, String code_save_path,String openid){
        try {
            /* 将网络资源地址传给,即赋值给url */
            URL url = new URL(fileUrl);

            /* 此为联系获得网络资源的固定格式用法，以便后面的in变量获得url截取网络资源的输入流 */
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            DataInputStream in = new DataInputStream(connection.getInputStream());

            /* 此处也可用BufferedInputStream与BufferedOutputStream  需要保存的路径*/
            DataOutputStream out = new DataOutputStream(new FileOutputStream(code_save_path + openid + head + ".png"));


            /* 将参数savePath，即将截取的图片的存储在本地地址赋值给out输出流所指定的地址 */
            byte[] buffer = new byte[1024];
            int count = 0;
            while ((count = in.read(buffer)) > 0)/* 将输入流以字节的形式读取并写入buffer中 */
            {
                out.write(buffer, 0, count);
            }
            out.close();/* 后面三行为关闭输入输出流以及网络资源的固定格式 */
            in.close();
            connection.disconnect();
            return code_save_path + openid + head + ".png"; /* 网络资源截取并存储本地成功返回true */

        } catch (Exception e) {
            return null;
        }
    }

    public static WxMpMaterialUploadResult QrCodeWithHeadImage(WxMpService wxMpService
            , String openid, String qrcodeUrl, String headImgUrl, BecApp becApp){

        String codeSavePath= QrCodeCreateUtil.download_picture(qrcodeUrl,"",becApp.getOtherCfgStr5(),openid);
        String pictureSavePath= QrCodeCreateUtil.download_picture(headImgUrl,"head",becApp.getOtherCfgStr5(),openid);
        QrCodeCreateUtil.gen_logo_qrcode(codeSavePath,pictureSavePath);

        WxMpMaterial wxMaterial = new WxMpMaterial();
        wxMaterial.setFile(new File(becApp.getOtherCfgStr5()+openid+".png"));
        wxMaterial.setName(openid+".png");
        try{
            WxMpMaterialUploadResult res =
                    wxMpService.getMaterialService().materialFileUpload("image", wxMaterial);
            return res;
        }
        catch(Exception e){
            System.out.println(e.getMessage());
            return null;

        }

    }

}

